package cmpe273.proj1.model;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

import cmpe273.proj1.utilities.Utilities;

public class Student extends Person {
	//public constants
	public static int MAX_LENGTH_STUDENTID = 11;
	
	//private members
	private Long id;
	private String studentId;
	private List<Course> enrolledCourses;
	
	//constructors
	public Student() {
		super();
		this.id = null;
		this.studentId = "";
		this.enrolledCourses = new ArrayList<Course>();
	}
	
	public Student(Long id, String studentId, Person person, List<Course> enrolledCourses) {
		super(person);
		this.id = id;
		this.studentId = studentId == null ? "" : studentId;
		this.enrolledCourses = enrolledCourses == null ? new ArrayList<Course>() : enrolledCourses;
	}

	//accessors
	public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
    
	public String getStudentId() {
		return studentId;
	}

	public void setStudentId(String studentId) {
		this.studentId = studentId;
	}

	public List<Course> getEnrolledCourses() {
		return enrolledCourses;
	}

	public void setEnrolledCourses(List<Course> enrolledCourses) {
		this.enrolledCourses = enrolledCourses;
	}
	
	//JSON utility
	public boolean loadStudent(JSONObject jsonObj) {
		try {
			if(!super.loadPerson(jsonObj))
				return false;
			
			this.studentId = jsonObj.getString("studentId");
			this.enrolledCourses = Course.toCourseList(jsonObj.getJSONArray("enrolledCourses"));
		} catch (JSONException e) {
			System.out.println("Invalid Student jsonObj: " + jsonObj.toString());
			return false;
		}
		return true;
	}
	
	public boolean loadStudent(String jsonString) {
		try {
			JSONObject obj = new JSONObject(jsonString);
			
			return loadStudent(obj);
		} catch (JSONException e) {
			System.out.println("Invalid Student jsonString: " + jsonString);
			return false;
		}
	}
	
	public String toJsonString() {
		String ret  = "{\"studentId\":\"" + studentId + super.toPartialJsonString() + ", \"enrolledCourses\":\"" + Course.toJsonArray(enrolledCourses) + "\"}";
		return ret;
	}
	
	public JSONObject toJsonObject()
	{
		return Utilities.toJsonObject(this.toJsonString());
	}
	
	//general utility
	public double getTuition() {
		return getEnrolledCourses().size() * Course.COURSE_COST;
	}

	//validation utilities
	public String validate() {
		StringBuilder sb = new StringBuilder();
		if(studentId.length() != MAX_LENGTH_STUDENTID)
			sb.append(String.format(Utilities.STRING_LENGTH_ERROR_NOTEQUAL, "Instructor ID", MAX_LENGTH_STUDENTID));

		if(!Person.validId(studentId))
			sb.append(String.format(Utilities.ID_FORMAT_ERROR));

		sb.append(super.validate());
		return sb.toString();
	}
	
	//Serializable Overrides
	/**
	 * The user ID is unique for each Student. So this should compare Student by ID only.
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object other) {
		return (other instanceof Student) && (id != null)
				? id.equals(((Student) other).id)
						: (other == this);
	}

	/**
	 * The user ID is unique for each Student. So Student with same ID should return same hashcode.
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		return (id != null) 
				? (this.getClass().hashCode() + id.hashCode()) 
						: super.hashCode();
	}

	/**
	 * Returns the String representation of this Student. Not required, it just pleases reading logs.
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return String.format("Instructor[id=%d,studentId=%s,numEnrolledCourses=%d,super=%s]", 
				id, getStudentId(), enrolledCourses.size(), super.toString());
	}
}
